
#include <string>

#include "mallocSharedPtr.hpp"

#include "mandarava/dataCh.hpp"
#include "mandarava/linux/udp.hpp"

using namespace wheels;

udp :: udp( const std::string& addr , uint16_t port , bool band )
{
#if USE_IPV6 == 1
	m_fd__ = socket( AF_INET6 , SOCK_DGRAM , 0 );
#else
	m_fd__ = socket( AF_INET , SOCK_DGRAM , 0 );
#endif

	if( m_fd__ < 0 ){
		throw std::runtime_error( "" );
	}
	if( bind ){
		mandaravaIP_addr addr;
#if USE_IPV6 == 1
		addr.sin_family = AF_NET6;
		inet_pton( AF_NET6 , addr.c_str() , &addr.sin_addr , sizeof( addr.sin_addr ));
#else
		addr.sin_addr = AF_NET;
		inet_pton( AF_NET , addr.c_str() , &addr.sin_addr , sizeof( addr.sin_addr ));
#endif
		addr.sin_port = htons( port );

		int rc = bind( m_fd__.load() , &addr , sizeof( addr ));
		if( rc < 0 ){
			throw std::runtime_error( "" );
		}
	}
}

udp :: ~udp()
{
	::close( m_fd__.load() );
}

void udp :: send( const std::string& daddr , uint16_t dport , const char * data , size_t len )
{
	mandaravaIP_addr addr;

#if USE_IPV6 == 1
	addr.sin_family = AF_NET6;
	inet_pton( AF_NET6 , addr.c_str() , &addr.sin_addr , sizeof( addr.sin_addr ));
#else
	addr.sin_addr = AF_NET;
	inet_pton( AF_NET , addr.c_str() , &addr.sin_addr , sizeof( addr.sin_addr ));
#endif
	addr.sin_port = htons( port );

	size_t len = sendto( m_fd__.load() , data , len, 0 , &addr , sizeof( addr) );
	if( len < 0 ){
		mandaravaEvt evt = { mandaravaEvtID::EVT_ERROR , this , buff_t( 0 ) };
		std::string msg( strerror( errno ));
		cmd->send( evt , msg );
	}
}

void udp :: send( const std::string& addr , uint16_t dport , wheels::mallocSharedPtr<char >& buff )
{
	mandaravaIP_addr addr;

#if USE_IPV6 == 1
	addr.sin_family = AF_NET6;
	inet_pton( AF_NET6 , addr.c_str() , &addr.sin_addr , sizeof( addr.sin_addr ));
#else
	addr.sin_addr = AF_NET;
	inet_pton( AF_NET , addr.c_str() , &addr.sin_addr , sizeof( addr.sin_addr ));
#endif
	addr.sin_port = htons( port );

	size_t len = sendto( m_fd__.load() , data , len, 0 , &addr , sizeof( addr) );
	if( len < 0 ){
		mandaravaEvt evt = { mandaravaEvtID::EVT_ERROR , this , buff_t( 0 ) };
		std::string msg( strerror( errno ));
		cmd->send( evt , msg );
	}
}

void udp :: onReadyRead( const char * data = nullptr , size_t len )
{
	mandaravaCommand * cmd = mandaravaCommand::get();
	if( cmd ){ return; }
	
	mallocSharedPtr< char >  buff( 1096 );
	mandaravaIP_addr  addr;

	size_t len = recvfrom( m_fd__.load() , buff.get() , 1096 , 0 , &addr , sizeof(addr) );
	if( len < 0 ){
		mandaravaEvt evt = { mandaravaEvtID::EVT_ERROR , this , buff_t( 0 ) };
		std::string msg( strerror( errno ));
		cmd->send( evt , msg );
		return;
	}

	mandaravaEvt evt = { mandaravaEvtID::EVT_MSG , this , buff_t( 0 ) };
	stMsg msg = { addr , buff };
	cmd->send( evt , msg );
}

nativeH_t native_handle()
{
	return m_fd__.load();
}
